package com.um.jdy.app.shop.manager;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import com.alipay.easysdk.factory.Factory;
import com.alipay.easysdk.kernel.util.ResponseChecker;
import com.alipay.easysdk.payment.common.models.AlipayTradeCreateResponse;
import com.github.binarywang.wxpay.bean.notify.WxPayOrderNotifyV3Result;
import com.github.binarywang.wxpay.bean.result.WxPayUnifiedOrderV3Result;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.um.jdy.app.activity.entity.vo.GroupOrderItemVO;
import com.um.jdy.common.commons.manager.WxManager;
import com.um.jdy.app.shop.entity.bo.GroupOrderBO;
import com.um.jdy.app.shop.entity.dto.ShopOrderPageDTO;
import com.um.jdy.app.shop.entity.vo.*;
import com.um.jdy.app.queue.enums.DelayedQueueKey;
import com.um.jdy.app.queue.service.RedissonDelayedQueueService;
import com.um.jdy.common.activity.service.CouponsService;
import com.um.jdy.common.activity.service.CouponsUserService;
import com.um.jdy.common.shop.entity.po.Courier;
import com.um.jdy.common.base.enums.YesOrNo;
import com.um.jdy.common.shop.service.CourierService;
import com.um.jdy.common.charge.code.OrderCode;
import com.um.jdy.common.commons.utils.Kuaidi100Util;
import com.um.jdy.common.finance.entity.po.PlatformBill;
import com.um.jdy.common.finance.enums.FinancialEnum;
import com.um.jdy.common.finance.service.PlatformBillService;
import com.um.jdy.common.market.entity.po.Group;
import com.um.jdy.common.market.entity.vo.GroupVO;
import com.um.jdy.common.market.service.GroupService;
import com.um.jdy.common.member.entity.po.MemberUser;
import com.um.jdy.common.member.enums.PayEnum;
import com.um.jdy.common.member.service.MemberUserService;
import com.um.jdy.common.shop.code.ShopOrderCode;
import com.um.jdy.common.shop.entity.po.Order;
import com.um.jdy.common.shop.entity.po.OrderGoods;
import com.um.jdy.common.shop.enums.OrderEnum;
import com.um.jdy.common.shop.service.GoodsOptionService;
import com.um.jdy.common.shop.service.OrderGoodsService;
import com.um.jdy.common.shop.service.ShopOrderService;
import com.um.springboot.starter.code.CommonCode;
import com.um.springboot.starter.entity.Page;
import com.um.springboot.starter.exception.ServiceException;
import com.um.springboot.starter.properties.HshProperties;
import com.um.springboot.starter.utils.JSONUtil;
import com.um.springboot.starter.utils.OrderUtil;
import com.um.springboot.starter.utils.PayUtil;
import com.um.springboot.starter.utils.condition.ConditionBuilder;
import com.um.weixin.pay.service.WxBasePayService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.util.*;
import java.util.stream.Collectors;


/**
 * @Title
 * @Description
 * @Author renjunwei
 * @Date 2023/5/22 10:37
 */
@Slf4j
@Service
public class ShopOrderManager {

    @Autowired
    ShopOrderService shopOrderService;

    @Autowired
    OrderGoodsService orderGoodsService;

    @Autowired
    MemberUserService memberUserService;

    @Autowired
    GroupService groupService;

    @Autowired
    GoodsOptionService goodsOptionService;

    @Autowired
    CouponsUserService couponsUserService;

    @Autowired
    PlatformBillService platformBillService;

    @Autowired
    CouponsService couponsService;

    @Autowired
    WxManager wxManager;

    @Autowired
    WxBasePayService wxBasePayService;

    @Autowired
    HshProperties hshProperties;

    @Autowired
    CourierService courierService;

    @Autowired
    RedissonDelayedQueueService redissonDelayedQueueService;

    /**
     * 分页查询我的订单
     * @param dto
     * @return
     */
    public Page<ShopOrderItemVO> getPage(ShopOrderPageDTO dto){
        Page<ShopOrderItemVO> page = new Page(dto);

        String memberUserId = memberUserService.get().getMemberUserId();
        Map<String, String> condition = ConditionBuilder.create()
                .put("o.member_user_id", memberUserId)
                .put("o.com_id",memberUserService.getComId())
                .put("o.status", dto.getStatus())
                .putLike("g.goods_name", dto.getName())
                .build();
        page = shopOrderService.getCMSViewModelPageBySqlName(page, "get_shop_order_page", "get_shop_order_count",
                ShopOrderItemVO.class, condition.keySet().toArray(new String[0]), condition.values().toArray(new String[0]),
                new ArrayList(), new String[]{}, new String[]{});
        page.getResult().stream().forEach(item -> {
            item.setGoods(getGoodsList(item.getShopOrderId()));
            if(OrderEnum.Type.Group.name().equals(item.getType())){
                Group group = groupService.getEntity(item.getMarketGroupId());
                List<GroupOrderBO> orderList = groupService.getViewModelList("get_group_order_list", GroupOrderBO.class,
                        new Object[]{group.getMarketGroupId(),group.getComId(), group.getShopOrderIds()});

                item.setGroup(BeanUtil.toBean(group, GroupVO.class));
                item.setGroupUsers(orderList);
            }
        });
        if(page.getPageNo() == 1){
            page.setExtraData(getStatus(memberUserId));
        }
        return page;
    }

    /**
     * 查询订单状态数
     * @param uid
     * @return
     */
    public OrderStatusNumVO getStatus(String uid){
        String comId = shopOrderService.getComId();
        Long unPayNum = shopOrderService.getCountBySqlName("get_shop_order_num", new Object[]{uid, OrderEnum.Status.UnPay.name(),comId});
        Long unSendNum = shopOrderService.getCountBySqlName("get_shop_order_num", new Object[]{uid, OrderEnum.Status.UnSend.name(),comId});
        Long unReceiveNum = shopOrderService.getCountBySqlName("get_shop_order_num", new Object[]{uid, OrderEnum.Status.UnReceive.name(),comId});
        Long unCommentNum = shopOrderService.getCountBySqlName("get_shop_order_num", new Object[]{uid, OrderEnum.Status.UnComment.name(),comId});
        OrderStatusNumVO orderStatusNumVO = new OrderStatusNumVO();
        orderStatusNumVO.setUnPayNum(unPayNum);
        orderStatusNumVO.setUnSendNum(unSendNum);
        orderStatusNumVO.setUnReceiveNum(unReceiveNum);
        orderStatusNumVO.setUnCommentNum(unCommentNum);
        return orderStatusNumVO;
    }

    /**
     * 更新订单收货地址
     * @param shopOrderId
     * @param memberAddressId
     */
    public void updateAddress(String shopOrderId, String memberAddressId){
        Order order = shopOrderService.getEntity(shopOrderId);
        if(null == order){
            throw new ServiceException(ShopOrderCode.OrderNoExist);
        }
        if (!StrUtil.equals(order.getStatus(), OrderEnum.Status.UnPay.name()) &&
                !StrUtil.equals(order.getStatus(), OrderEnum.Status.UnSend.name()) &&
                !StrUtil.equals(order.getStatus(), OrderEnum.Status.UnGroup.name())) {
            throw new ServiceException("修改失败，该订单"+ OrderEnum.Status.valueOf(order.getStatus()).getValue()+"！");
        }
        // TODO 暂时不做， 修改收货地址运费也变了
    }

    /**
     * 查询订单详情
     * @param shopOrderId
     * @return
     */
    public OrderDetailVO get(String shopOrderId){
        Order order = shopOrderService.getEntity(new String[]{"member_user_id", "shop_order_id"},
                new String[]{memberUserService.get().getMemberUserId(), shopOrderId});
        if(null == order){
            throw new ServiceException(ShopOrderCode.OrderNoExist);
        }
        List<OrderGoodsItemVO> goodsList = this.getGoodsList(shopOrderId);

        OrderDetailVO detail = BeanUtil.toBean(order, OrderDetailVO.class);
        detail.setGoods(goodsList);

        if(StrUtil.equals(order.getType(), OrderEnum.Type.Group.name())){
            Group group = groupService.getEntity(order.getMarketGroupId());
            List<GroupOrderBO> orderList = groupService.getViewModelList("get_group_order_list", GroupOrderBO.class,
                    new Object[]{group.getMarketGroupId(),group.getComId(), group.getShopOrderIds()});

            detail.setGroup(BeanUtil.toBean(group, GroupVO.class));
            detail.setGroupUsers(orderList);
        }

        return detail;
    }

    /**
     * 查询订单商品列表
     *
     * @param shopOrderId
     * @return
     */
    public List<OrderGoodsItemVO> getGoodsList(String shopOrderId) {
        return shopOrderService.getViewModelList("get_order_goods_list", OrderGoodsItemVO.class, new Object[]{shopOrderId,shopOrderService.getComId()});
    }

    /**
     * 支付订单
     * @param shopOrderId
     * @param payWay
     * @return
     */
    public Map pay(String shopOrderId, PayEnum.PayWay payWay){
        MemberUser user = memberUserService.get();
        Order order = shopOrderService.getEntity(new String[]{"member_user_id", "shop_order_id"},
                new String[]{user.getMemberUserId(), shopOrderId});
        if (null == order || !StrUtil.equals(order.getStatus(), OrderEnum.Status.UnPay.name())) {
            throw new ServiceException("支付失败，该订单"+ OrderEnum.Status.valueOf(order.getStatus()).getValue()+"！");
        }

        return pay(order, user.getMiniOpenId());
    }

    /**
     * 支付订单
     * @param order
     * @param openId
     * @return
     */
    public Map pay(Order order, String openId){

        Map returnData = new HashMap();

        String notifyUrl = StrUtil.builder(hshProperties.getConfig().getDomain(),
                "/api/v1/shop/order/%s/notify/", order.getComId()).toString();

        switch (PayEnum.PayWay.valueOf(order.getPayWay())){
            case Wxpay:
                WxPayUnifiedOrderV3Result.JsapiResult jsapiResult;
                try {
                    wxManager.getPayService(order.getComId());
                    jsapiResult = wxBasePayService.createOrderByJsapi(order.getOutTradeNo(), openId,
                            PayUtil.toTotalFee(order.getPayment()), PayEnum.Title.Shop.getValue(), String.format(notifyUrl, "wxpay"));
                } catch (WxPayException e) {
                    log.error("微信支付创建订单失败", e);
                    throw new ServiceException(e.getCustomErrorMsg());
                }

                returnData.putAll(BeanUtil.beanToMap(jsapiResult, true, true));
                break;

            case Alipay:
                AlipayTradeCreateResponse alipayTradeCreateResponse = null;
                try {
                    alipayTradeCreateResponse = Factory.Payment.Common()
                            .asyncNotify(String.format(notifyUrl, "alipay"))
                            .optional("timeout_express", "10m") //订单超时时间
                            .create(PayEnum.Title.Deposit.getValue(), order.getOutTradeNo(),
                                    PayUtil.toDoubleAmountStr(order.getPayment()), openId);
                } catch (Exception e) {
                    log.error("支付宝创建订单失败", e);
                    throw new ServiceException(OrderCode.CreateAlipayOrderFailure);
                }

                if (!ResponseChecker.success(alipayTradeCreateResponse)) {
                    throw new ServiceException(CommonCode.Failed.getCode(), alipayTradeCreateResponse.getSubMsg());
                }

                returnData.putAll(alipayTradeCreateResponse.toMap());
                break;
        }
        return returnData;
    }

    /**
     * 微信支付成功回调
     *
     * @param request
     */
    public void wxPayNotify(HttpServletRequest request, String comId) {
        WxPayOrderNotifyV3Result wxPayOrderNotifyV3Result = null;
        try {
            wxManager.getPayService(comId);
            wxPayOrderNotifyV3Result = wxBasePayService.parseOrderNotify(request);
        } catch (WxPayException e) {
            log.error("解析微信支付通知失败", e);
            return;
        }

        WxPayOrderNotifyV3Result.DecryptNotifyResult result = wxPayOrderNotifyV3Result.getResult();
        if(null == result){
            log.error("解析微信支付通知结果为null");
            return;
        }

        Order order = shopOrderService.getRow("out_trade_no", result.getOutTradeNo());
        if (null == order) {
            log.error("微信订单" + result.getOutTradeNo() + "不存在！");
            return;
        }

        payNotify(order, DateUtil.parse(result.getSuccessTime()));
    }

    /**
     * 支付回调
     *
     * @param order
     * @param payTime
     */
    public void payNotify(Order order, Date payTime) {
        order.setStatus(OrderEnum.Status.UnSend.name());
        order.setPayTime(payTime);
        if(StrUtil.equals(order.getType(), OrderEnum.Type.Group.name())){
            order.setStatus(OrderEnum.Status.UnGroup.name());

            Group group = groupService.getRow(order.getMarketGroupId());
            List<Order> groupOrderList = shopOrderService.getListBySqlName("get_paid_order_list_by_group",
                    new Object[]{group.getMarketGroupId(),group.getComId()});
            if(groupOrderList.size() + 1 == group.getGroupNum()){
                groupOrderList.stream().forEach(item -> {
                    item.setStatus(OrderEnum.Status.UnSend.name());
                    shopOrderService.saveRow(item);
                });
                order.setStatus(OrderEnum.Status.UnSend.name());

                group.setStatus(OrderEnum.GroupStatus.Opened.name());
                groupService.saveRow(group);

                //删除关闭拼团延迟队列
                redissonDelayedQueueService.removeQueueElement(group.getMarketGroupId(), DelayedQueueKey.CloseGroup.name());
            }
        }
        shopOrderService.saveRow(order);

        //删除超时未支付延迟队列
        redissonDelayedQueueService.removeQueueElement(order.getShopOrderId(), DelayedQueueKey.CancelOrder.name());

        List<PlatformBill> billList = platformBillService.getRows(new String[]{"order_no"}, new String[]{order.getOrderNo()});
        billList.stream().forEach(item -> {
            item.setStatus(FinancialEnum.BillStatus.Effective.name());
            platformBillService.saveRow(item);
        });
    }

    /**
     * 取消订单
     *
     * @param shopOrderId
     * @return
     */
    public void cancel(String shopOrderId) {
        this.cancel(shopOrderId, memberUserService.get().getMemberUserId());
    }

    /**
     * 取消订单
     *
     * @param shopOrderId
     * @param memberUserId
     * @return
     */
    public void cancel(String shopOrderId, String memberUserId) {
        Order order = shopOrderService.getRow(new String[]{"member_user_id", "shop_order_id"},
                new String[]{memberUserId, shopOrderId});
        if (null == order || !StrUtil.equals(order.getStatus(), OrderEnum.Status.UnPay.name())) {
            throw new ServiceException("取消失败，该订单"+ OrderEnum.Status.valueOf(order.getStatus()).getValue()+"！");
        }

        order.setStatus(OrderEnum.Status.Cancelled.name());
        shopOrderService.updateRow(order);

        //退回库存
        List<OrderGoods> goodsList = orderGoodsService.getRows("shop_order_id", shopOrderId);
        goodsList.stream().forEach(item -> {
            goodsOptionService.addStock(item.getShopGoodsOptionId(), item.getNum());
            goodsOptionService.addActivityStock(item.getMarketActivityGoodsOptionId(), item.getNum());
        });

        //退回优惠券
        couponsUserService.returnCouponsUse(order.getActivityCouponsUserId());

        List<PlatformBill> billList = platformBillService.getRows("order_no", order.getOrderNo());
        billList.stream().forEach(item -> {
            item.setStatus(FinancialEnum.BillStatus.Invalided.name());
            platformBillService.updateRow(item);
        });

        if(StrUtil.equals(order.getType(), OrderEnum.Type.Group.name())){
            Group group = groupService.getRow(order.getMarketGroupId());
            if(null == group){
                return;
            }
            
            //如果拼团没有人了就关闭团
            List<GroupOrderItemVO> groupOrderList = shopOrderService.getViewModelList("get_effective_group_order_list",
                    GroupOrderItemVO.class, new Object[]{order.getMarketGroupId(),group.getComId()});
            if(groupOrderList.size() == 0){
                group.setStatus(OrderEnum.GroupStatus.Invalid.name());
                group.setShopOrderIds(shopOrderId);
                groupService.updateRow(group);
                log.info("系统关闭没有团员的团购，拼团id：{}", order.getMarketGroupId());
            }else{
                group.setShopOrderIds(groupOrderList.stream().map(item -> item.getShopOrderId()).collect(Collectors.joining(",")));
                groupService.updateRow(group);
            }
        }

    }

    /**
     * 拼团订单未成团退款
     * @param shopOrderId
     * @return
     */
    public void groupRefund(String shopOrderId, String memberUserId) {
        Order order = shopOrderService.getRow(new String[]{"member_user_id", "shop_order_id"},
                new String[]{memberUserId, shopOrderId});
        if (null == order || !StrUtil.equals(order.getStatus(), OrderEnum.Status.UnGroup.name())) {
            throw new ServiceException("取消失败，该订单"+ OrderEnum.Status.valueOf(order.getStatus()).getValue()+"！");
        }
        OrderGoods orderGoods = orderGoodsService.getRow("shop_order_id", shopOrderId);

        order.setWxRefundNo(OrderUtil.getWxOrderNo());

        if (PayEnum.PayWay.Wxpay.name().equals(order.getPayWay())) {
            try {
                wxManager.getPayService(order.getComId());
                wxBasePayService.refundOrder(order.getOutTradeNo(), order.getWxRefundNo(),
                        PayUtil.toTotalFee(order.getPayment()), PayUtil.toTotalFee(order.getPayment()));
            } catch (Exception ex) {
                log.error(StrUtil.format("拼团订单[{}]微信退款错误", order.getOrderNo()), ex);
            }

        } else if (PayEnum.PayWay.Alipay.name().equals(order.getPayWay())) {

            try {
                // TODO 支付宝退款不能用， 需要做根据comid切换到对应服务商
//                Map refundResult = payService.refund(outTradeNo, payUtil.toDoubleAmount(totalFee));
            } catch (Exception ex) {
                log.error(StrUtil.format("拼团订单[{}]支付宝退款错误", order.getOrderNo()), ex);
            }
        }

        order.setStatus(OrderEnum.Status.Return.name());
        shopOrderService.saveRow(order);

        goodsOptionService.addStock(orderGoods.getShopGoodsOptionId(), orderGoods.getNum());
        goodsOptionService.addActivityStock(orderGoods.getMarketActivityGoodsOptionId(), orderGoods.getNum());
        couponsUserService.returnCouponsUse(order.getActivityCouponsUserId());

        List<PlatformBill> billList = platformBillService.getRows("order_no", order.getOrderNo());
        billList.stream().forEach(item -> {
            item.setStatus(FinancialEnum.BillStatus.Invalided.name());
            platformBillService.updateRow(item);
        });

    }



    /**
     * 删除订单
     *
     * @param shopOrderId
     * @return
     */
    public void delete(String shopOrderId) {
        Order order = shopOrderService.getEntity(new String[]{"member_user_id", "shop_order_id"},
                new String[]{memberUserService.get().getMemberUserId(), shopOrderId});
        if (null == order || (!StrUtil.equals(order.getStatus(), OrderEnum.Status.Cancelled.name()) &&
                !StrUtil.equals(order.getStatus(), OrderEnum.Status.UnPay.name()) &&
                !StrUtil.equals(order.getStatus(), OrderEnum.Status.Return.name()) &&
                !StrUtil.equals(order.getStatus(), OrderEnum.Status.Completed.name()))) {
            throw new ServiceException("删除失败，该订单"+ OrderEnum.Status.valueOf(order.getStatus()).getValue()+"！");
        }

        order.setUserDelete(YesOrNo.Yes.name());
        shopOrderService.update(order);
    }

    /**
     * 确认收货
     *
     * @param shopOrderId
     * @return
     */
    public void receive(String shopOrderId) {
        receive(shopOrderId, memberUserService.get().getMemberUserId());
    }

    /**
     * 确认收货
     *
     * @param shopOrderId
     * @return
     */
    public void receive(String shopOrderId, String memberUserId) {
        Order order = shopOrderService.getRow(new String[]{"member_user_id", "shop_order_id"},
                new String[]{memberUserId, shopOrderId});
        if (null == order || !StrUtil.equals(order.getStatus(), OrderEnum.Status.UnReceive.name())) {
            throw new ServiceException("确认收货失败，该订单"+ OrderEnum.Status.valueOf(order.getStatus()).getValue()+"！");
        }

        order.setStatus(OrderEnum.Status.UnComment.name());
        order.setReceivingTime(DateUtil.date());
        shopOrderService.saveRow(order);

        if(StrUtil.isNotEmpty(order.getGiftActivityCouponsIds())){
            List<String> giftActivityCouponsIdList = JSONUtil.parseJSONToList(order.getGiftActivityCouponsIds());
            giftActivityCouponsIdList.stream().forEach(item -> couponsService.receive(item, order.getMemberUserId()));

        }
    }

    /**
     * 查询物流轨迹
     *
     * @param shopOrderId
     * @return
     */
    public Object getExpressTrack(String shopOrderId) {
        OrderDetailVO order = get(shopOrderId);
        Courier courier = courierService.getEntity("name", order.getCourier());
        Object expressTrack = Kuaidi100Util.queryTrack(Optional.ofNullable(courier).orElseGet(Courier::new).getCode(),
                order.getCourierNo(), order.getPhone());
        return expressTrack;
    }

    /**
     * 关闭拼团
     * @param marketGroupId
     */
     public void closeGroup(String marketGroupId){
         Group group = groupService.getRow(marketGroupId);
         if(null == group || !OrderEnum.GroupStatus.Unopen.name().equals(group.getStatus())){
             return;
         }
         List<Order> orderList = shopOrderService.getRows(new String[]{"market_group_id"}, new String[]{marketGroupId});
         for(Order order : orderList){
             if(OrderEnum.Status.UnPay.name().equals(order.getStatus())){
                 this.cancel(order.getShopOrderId(), order.getMemberUserId());
             }else if(OrderEnum.Status.UnGroup.name().equals(order.getStatus())){
                 this.groupRefund(order.getShopOrderId(), order.getMemberUserId());
             }
         }
         group.setStatus(OrderEnum.GroupStatus.Invalid.name());
         groupService.saveRow(group);
     }


}
